use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
use argon2::password_hash::{rand_core::OsRng, SaltString};
use aes_gcm::{Aes256Gcm, Key, Nonce, KeyInit};
use aes_gcm::aead::Aead;
use rand::Rng;
use base64::{Engine as _, engine::general_purpose};
use zeroize::Zeroize;
use serde::{Deserialize, Serialize};
use tauri::State;
use rusqlite::params;
use std::sync::Mutex;

use crate::commands::storage::AppDb;

/// Global master password cache (stored in memory only, cleared on logout)
pub struct MasterPasswordCache(pub Mutex<Option<String>>);

/// Password data structure for encryption/decryption
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PasswordData {
    pub title: String,
    pub username: Option<String>,
    pub password: String,
    pub website: Option<String>,
    pub notes: Option<String>,
}

/// Encrypted password data stored in database
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EncryptedPasswordData {
    pub id: Option<i64>,
    pub title: String,
    pub username: Option<String>,
    pub encrypted_password: String,
    pub website: Option<String>,
    pub notes: Option<String>,
    pub created_at: Option<String>,
    pub updated_at: Option<String>,
}

/// Check if master password exists in database
#[tauri::command]
pub async fn check_master_password_exists(db: State<'_, AppDb>) -> Result<bool, String> {
    log::info!("=== Checking master password exists ===");
    let conn = db.0.lock().map_err(|e| format!("Failed to acquire database lock: {}", e))?;
    
    // First, list all keys in app_settings for debugging
    let mut stmt = conn.prepare("SELECT key FROM app_settings")
        .map_err(|e| format!("Failed to prepare query: {}", e))?;
    let keys: Result<Vec<String>, _> = stmt
        .query_map([], |row| row.get(0))
        .map_err(|e| format!("Failed to query keys: {}", e))?
        .collect();
    
    match keys {
        Ok(key_list) => {
            log::info!("All keys in app_settings: {:?}", key_list);
        }
        Err(e) => {
            log::error!("Failed to list keys: {}", e);
        }
    }
    
    let exists: bool = conn
        .query_row(
            "SELECT COUNT(*) FROM app_settings WHERE key = 'master_password_hash'",
            [],
            |row| {
                let count: i64 = row.get(0)?;
                log::info!("Master password count: {}", count);
                Ok(count > 0)
            },
        )
        .map_err(|e| format!("Failed to query master password: {}", e))?;
    
    log::info!("Master password exists: {}", exists);
    log::info!("=== End check ===");
    Ok(exists)
}

/// Set master password (first time setup)
#[tauri::command]
pub async fn set_master_password(
    db: State<'_, AppDb>,
    password: String,
) -> Result<(), String> {
    log::info!("=== Setting master password ===");
    
    // Validate password strength
    if password.len() < 8 {
        return Err("密码长度至少需要8个字符".to_string());
    }
    
    if !password.chars().any(|c| c.is_ascii_uppercase()) {
        return Err("密码必须包含至少一个大写字母".to_string());
    }
    
    if !password.chars().any(|c| c.is_ascii_lowercase()) {
        return Err("密码必须包含至少一个小写字母".to_string());
    }
    
    if !password.chars().any(|c| c.is_ascii_digit()) {
        return Err("密码必须包含至少一个数字".to_string());
    }
    
    if !password.chars().any(|c| "!@#$%^&*()_+-=[]{}|;:,.<>?".contains(c)) {
        return Err("密码必须包含至少一个特殊字符".to_string());
    }
    
    // Hash password using Argon2
    let salt = SaltString::generate(&mut OsRng);
    let argon2 = Argon2::default();
    
    let password_hash = argon2
        .hash_password(password.as_bytes(), &salt)
        .map_err(|e| format!("密码哈希失败: {}", e))?
        .to_string();
    
    log::info!("Password hash generated successfully");
    
    // Store hash in database
    let conn = db.0.lock().map_err(|e| e.to_string())?;
    
    conn.execute(
        "INSERT OR REPLACE INTO app_settings (key, value, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP)",
        params!["master_password_hash", password_hash],
    )
    .map_err(|e| format!("保存密码哈希失败: {}", e))?;
    
    log::info!("Master password hash saved to database");
    
    // Verify it was saved
    let verify: Result<String, _> = conn.query_row(
        "SELECT value FROM app_settings WHERE key = 'master_password_hash'",
        [],
        |row| row.get(0),
    );
    
    match verify {
        Ok(_) => log::info!("Verified: Master password hash exists in database"),
        Err(e) => log::warn!("WARNING: Failed to verify master password hash: {}", e),
    }
    
    log::info!("=== End setting master password ===");
    Ok(())
}

/// Verify master password
#[tauri::command]
pub async fn verify_master_password(
    db: State<'_, AppDb>,
    password_cache: State<'_, MasterPasswordCache>,
    password: String,
) -> Result<bool, String> {
    let conn = db.0.lock().map_err(|e| e.to_string())?;
    
    let stored_hash: String = conn
        .query_row(
            "SELECT value FROM app_settings WHERE key = 'master_password_hash'",
            [],
            |row| row.get(0),
        )
        .map_err(|_| "未找到主密码哈希".to_string())?;
    
    let parsed_hash = PasswordHash::new(&stored_hash)
        .map_err(|e| format!("解析密码哈希失败: {}", e))?;
    
    let argon2 = Argon2::default();
    let is_valid = argon2.verify_password(password.as_bytes(), &parsed_hash).is_ok();
    
    // If password is valid, cache it in memory
    if is_valid {
        let mut cache = password_cache.0.lock().map_err(|e| e.to_string())?;
        *cache = Some(password);
    }
    
    Ok(is_valid)
}

/// Generate encryption key from master password
fn derive_encryption_key(master_password: &str) -> Result<[u8; 32], String> {
    let salt = b"password_manager_salt"; // Fixed salt for key derivation
    let argon2 = Argon2::default();
    
    let mut key = [0u8; 32];
    argon2
        .hash_password_into(master_password.as_bytes(), salt, &mut key)
        .map_err(|e| format!("密钥派生失败: {}", e))?;
    
    Ok(key)
}

/// Encrypt password data
#[tauri::command]
pub async fn encrypt_password_data(
    password_cache: State<'_, MasterPasswordCache>,
    password_data: PasswordData,
) -> Result<EncryptedPasswordData, String> {
    // Get master password from cache
    let cache = password_cache.0.lock().map_err(|e| e.to_string())?;
    let master_password = cache.as_ref()
        .ok_or_else(|| "未找到主密码，请重新登录".to_string())?;
    
    // Derive encryption key
    let key_bytes = derive_encryption_key(master_password)?;
    let key = Key::<Aes256Gcm>::from_slice(&key_bytes);
    let cipher = Aes256Gcm::new(key);
    
    // Generate random nonce
    let mut nonce_bytes = [0u8; 12];
    rand::thread_rng().fill(&mut nonce_bytes);
    let nonce = Nonce::from_slice(&nonce_bytes);
    
    // Encrypt password
    let encrypted_password = cipher
        .encrypt(nonce, password_data.password.as_bytes())
        .map_err(|e| format!("密码加密失败: {}", e))?;
    
    // Combine nonce and encrypted data
    let mut encrypted_data = nonce_bytes.to_vec();
    encrypted_data.extend_from_slice(&encrypted_password);
    
    // Encode as base64
    let encrypted_password_b64 = general_purpose::STANDARD.encode(&encrypted_data);
    
    // Clear sensitive data
    let mut key_bytes = key_bytes;
    key_bytes.zeroize();
    
    Ok(EncryptedPasswordData {
        id: None,
        title: password_data.title,
        username: password_data.username,
        encrypted_password: encrypted_password_b64,
        website: password_data.website,
        notes: password_data.notes,
        created_at: None,
        updated_at: None,
    })
}

/// Decrypt password data
#[tauri::command]
pub async fn decrypt_password_data(
    password_cache: State<'_, MasterPasswordCache>,
    encrypted_data: EncryptedPasswordData,
) -> Result<PasswordData, String> {
    // Get master password from cache
    let cache = password_cache.0.lock().map_err(|e| e.to_string())?;
    let master_password = cache.as_ref()
        .ok_or_else(|| "未找到主密码，请重新登录".to_string())?;
    
    // Derive encryption key
    let key_bytes = derive_encryption_key(master_password)?;
    let key = Key::<Aes256Gcm>::from_slice(&key_bytes);
    let cipher = Aes256Gcm::new(key);
    
    // Decode from base64
    let encrypted_data_bytes = general_purpose::STANDARD
        .decode(&encrypted_data.encrypted_password)
        .map_err(|e| format!("Base64解码失败: {}", e))?;
    
    if encrypted_data_bytes.len() < 12 {
        return Err("加密数据格式错误".to_string());
    }
    
    // Extract nonce and encrypted password
    let nonce_bytes = &encrypted_data_bytes[..12];
    let encrypted_password = &encrypted_data_bytes[12..];
    
    let nonce = Nonce::from_slice(nonce_bytes);
    
    // Decrypt password
    let decrypted_password = cipher
        .decrypt(nonce, encrypted_password)
        .map_err(|e| format!("密码解密失败: {}", e))?;
    
    let password = String::from_utf8(decrypted_password)
        .map_err(|e| format!("密码解码失败: {}", e))?;
    
    // Clear sensitive data
    let mut key_bytes = key_bytes;
    key_bytes.zeroize();
    
    Ok(PasswordData {
        title: encrypted_data.title,
        username: encrypted_data.username,
        password,
        website: encrypted_data.website,
        notes: encrypted_data.notes,
    })
}

/// Save encrypted password to database
#[tauri::command]
pub async fn save_password(
    db: State<'_, AppDb>,
    encrypted_data: EncryptedPasswordData,
) -> Result<i64, String> {
    let conn = db.0.lock().map_err(|e| e.to_string())?;
    
    let _id = conn.execute(
        "INSERT INTO passwords (title, username, encrypted_password, website, notes, created_at, updated_at) VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)",
        params![
            encrypted_data.title,
            encrypted_data.username,
            encrypted_data.encrypted_password,
            encrypted_data.website,
            encrypted_data.notes
        ],
    )
    .map_err(|e| format!("保存密码失败: {}", e))?;
    
    Ok(conn.last_insert_rowid())
}

/// Get all encrypted passwords from database
#[tauri::command]
pub async fn get_passwords(db: State<'_, AppDb>) -> Result<Vec<EncryptedPasswordData>, String> {
    let conn = db.0.lock().map_err(|e| e.to_string())?;
    
    let mut stmt = conn
        .prepare("SELECT id, title, username, encrypted_password, website, notes, created_at, updated_at FROM passwords ORDER BY created_at DESC")
        .map_err(|e| e.to_string())?;
    
    let password_iter = stmt
        .query_map([], |row| {
            Ok(EncryptedPasswordData {
                id: Some(row.get(0)?),
                title: row.get(1)?,
                username: row.get(2)?,
                encrypted_password: row.get(3)?,
                website: row.get(4)?,
                notes: row.get(5)?,
                created_at: Some(row.get(6)?),
                updated_at: Some(row.get(7)?),
            })
        })
        .map_err(|e| e.to_string())?;
    
    let mut passwords = Vec::new();
    for password in password_iter {
        passwords.push(password.map_err(|e| e.to_string())?);
    }
    
    Ok(passwords)
}

/// Delete password from database
#[tauri::command]
pub async fn delete_password(db: State<'_, AppDb>, id: i64) -> Result<(), String> {
    let conn = db.0.lock().map_err(|e| e.to_string())?;
    
    conn.execute("DELETE FROM passwords WHERE id = ?", params![id])
        .map_err(|e| format!("删除密码失败: {}", e))?;
    
    Ok(())
}

/// Clear cached master password (logout)
#[tauri::command]
pub async fn clear_master_password_cache(
    password_cache: State<'_, MasterPasswordCache>,
) -> Result<(), String> {
    let mut cache = password_cache.0.lock().map_err(|e| e.to_string())?;
    *cache = None;
    Ok(())
}

/// Change master password - re-encrypts all stored passwords
#[tauri::command]
pub async fn change_master_password(
    db: State<'_, AppDb>,
    password_cache: State<'_, MasterPasswordCache>,
    current_password: String,
    new_password: String,
) -> Result<(), String> {
    log::info!("=== Changing master password ===");
    
    // 1. Verify current password
    let conn = db.0.lock().map_err(|e| e.to_string())?;
    
    let stored_hash: String = conn
        .query_row(
            "SELECT value FROM app_settings WHERE key = 'master_password_hash'",
            [],
            |row| row.get(0),
        )
        .map_err(|_| "未找到主密码".to_string())?;
    
    let parsed_hash = PasswordHash::new(&stored_hash)
        .map_err(|e| format!("解析密码哈希失败: {}", e))?;
    
    let argon2 = Argon2::default();
    if argon2.verify_password(current_password.as_bytes(), &parsed_hash).is_err() {
        return Err("当前密码错误".to_string());
    }
    
    log::info!("Current password verified");
    
    // 2. Validate new password strength
    if new_password.len() < 8 {
        return Err("新密码长度至少需要8个字符".to_string());
    }
    
    if !new_password.chars().any(|c| c.is_ascii_uppercase()) {
        return Err("新密码必须包含至少一个大写字母".to_string());
    }
    
    if !new_password.chars().any(|c| c.is_ascii_lowercase()) {
        return Err("新密码必须包含至少一个小写字母".to_string());
    }
    
    if !new_password.chars().any(|c| c.is_ascii_digit()) {
        return Err("新密码必须包含至少一个数字".to_string());
    }
    
    if !new_password.chars().any(|c| "!@#$%^&*()_+-=[]{}|;:,.<>?".contains(c)) {
        return Err("新密码必须包含至少一个特殊字符".to_string());
    }
    
    log::info!("New password validated");
    
    // 3. Get all encrypted passwords
    let mut stmt = conn
        .prepare("SELECT id, encrypted_password FROM passwords")
        .map_err(|e| format!("查询密码失败: {}", e))?;
    
    let password_records: Vec<(i64, String)> = stmt
        .query_map([], |row| {
            Ok((row.get(0)?, row.get(1)?))
        })
        .map_err(|e| format!("读取密码失败: {}", e))?
        .collect::<Result<Vec<_>, _>>()
        .map_err(|e| format!("收集密码失败: {}", e))?;
    
    drop(stmt);
    
    log::info!("Found {} passwords to re-encrypt", password_records.len());
    
    // 4. Decrypt all passwords with current password and re-encrypt with new password
    let current_key = derive_encryption_key(&current_password)?;
    let current_cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(&current_key));
    
    let new_key = derive_encryption_key(&new_password)?;
    let new_cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(&new_key));
    
    let mut re_encrypted_passwords: Vec<(i64, String)> = Vec::new();
    
    for (id, encrypted_data_b64) in password_records {
        // Decrypt with current password
        let encrypted_data_bytes = general_purpose::STANDARD
            .decode(&encrypted_data_b64)
            .map_err(|e| format!("Base64解码失败: {}", e))?;
        
        if encrypted_data_bytes.len() < 12 {
            return Err("加密数据格式错误".to_string());
        }
        
        let nonce_bytes = &encrypted_data_bytes[..12];
        let encrypted_password = &encrypted_data_bytes[12..];
        let nonce = Nonce::from_slice(nonce_bytes);
        
        let decrypted_password = current_cipher
            .decrypt(nonce, encrypted_password)
            .map_err(|e| format!("密码解密失败: {}", e))?;
        
        // Re-encrypt with new password
        let mut new_nonce_bytes = [0u8; 12];
        rand::thread_rng().fill(&mut new_nonce_bytes);
        let new_nonce = Nonce::from_slice(&new_nonce_bytes);
        
        let new_encrypted_password = new_cipher
            .encrypt(new_nonce, decrypted_password.as_ref())
            .map_err(|e| format!("密码重新加密失败: {}", e))?;
        
        let mut new_encrypted_data = new_nonce_bytes.to_vec();
        new_encrypted_data.extend_from_slice(&new_encrypted_password);
        
        let new_encrypted_data_b64 = general_purpose::STANDARD.encode(&new_encrypted_data);
        re_encrypted_passwords.push((id, new_encrypted_data_b64));
    }
    
    log::info!("Re-encrypted all passwords");
    
    // 5. Generate new password hash
    let salt = SaltString::generate(&mut OsRng);
    let new_password_hash = argon2
        .hash_password(new_password.as_bytes(), &salt)
        .map_err(|e| format!("新密码哈希失败: {}", e))?
        .to_string();
    
    log::info!("Generated new password hash");
    
    // 6. Update all passwords in database (use transaction for atomicity)
    conn.execute("BEGIN TRANSACTION", [])
        .map_err(|e| format!("开始事务失败: {}", e))?;
    
    for (id, new_encrypted_data) in re_encrypted_passwords {
        conn.execute(
            "UPDATE passwords SET encrypted_password = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?",
            params![new_encrypted_data, id],
        )
        .map_err(|e| {
            let _ = conn.execute("ROLLBACK", []);
            format!("更新密码失败: {}", e)
        })?;
    }
    
    // 7. Update master password hash
    conn.execute(
        "UPDATE app_settings SET value = ?, updated_at = CURRENT_TIMESTAMP WHERE key = 'master_password_hash'",
        params![new_password_hash],
    )
    .map_err(|e| {
        let _ = conn.execute("ROLLBACK", []);
        format!("更新主密码哈希失败: {}", e)
    })?;
    
    conn.execute("COMMIT", [])
        .map_err(|e| format!("提交事务失败: {}", e))?;
    
    log::info!("Committed all changes");
    
    // 8. Update password cache
    let mut cache = password_cache.0.lock().map_err(|e| e.to_string())?;
    *cache = Some(new_password);
    
    log::info!("=== Master password changed successfully ===");
    
    Ok(())
}
